﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.IE;
using NPMonitor.Utility;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Globalization;
using System.Net.Sockets;

namespace NPMonitor.Library.Tests.Utility.WebDriver
{
    [TestClass]
    public class InternetExploreDriverTest
    {
        [TestMethod]
        public void ExecuteBuy360Test()
        {
            SubIEDriver webDriver = new SubIEDriver();

            try
            {
                webDriver.Start();

                webDriver.GoToUrl("http://www.360buy.com/");
                Thread.Sleep(5000);
            }
            finally
            {
                webDriver.DoQuit();
            }
        }

        public class SubIEDriver
        {
            Process driverServiceProcess;
            Uri remoteServerUri = null;
            TimeSpan serverResponseTimeout = TimeSpan.FromSeconds(60.0);
            bool enableKeepAlive = true;
            SessionId sessionId = null;
            int driverServicePort = FindFreePort();
            string driverServiceExecutableName = "IEDriverServer.exe";
            string driverServicePath = @"D:\git\DSM_P\NPMonitor\NPMonitor\packages\Libraries";
            DesiredCapabilities capabilities = null;

            public SubIEDriver()
            {
                capabilities = new OpenQA.Selenium.Remote.DesiredCapabilities();
                capabilities.SetCapability("ignoreProtectedModeSettings", true);

                remoteServerUri = ServiceUrl;
            }

            public Uri ServiceUrl
            {
                get
                {
                    return new Uri(string.Format(CultureInfo.InvariantCulture, "http://localhost:{0}", new object[] { this.driverServicePort }));
                }
            }

            protected string CommandLineArguments
            {
                get
                {
                    StringBuilder builder = new StringBuilder();
                    builder.Append(string.Format(CultureInfo.InvariantCulture, "-port={0}", new object[] { this.driverServicePort }));

                    return builder.ToString();
                }
            }

            public void GoToUrl(string url)
            {
                Dictionary<string, object> parameters = new Dictionary<string, object>();

                parameters.Add("url", url);
                this.Execute(DriverCommand.Get, parameters);
            }

            public void DoQuit()
            {
                this.Execute(DriverCommand.Close, null);

                this.Stop();
            }

            public void Start()
            {
                this.driverServiceProcess = new Process();
                this.driverServiceProcess.StartInfo.FileName = Path.Combine(this.driverServicePath, this.driverServiceExecutableName);
                this.driverServiceProcess.StartInfo.Arguments = this.CommandLineArguments;
                this.driverServiceProcess.StartInfo.UseShellExecute = false;
                this.driverServiceProcess.Start();
                DateTime time2 = DateTime.Now.Add(TimeSpan.FromSeconds(20.0));
                Uri requestUri = new Uri(this.ServiceUrl, new Uri("status", UriKind.Relative));

                HttpWebRequest request = WebRequest.Create(requestUri) as HttpWebRequest;
                bool flag = false;
                while (!flag && (DateTime.Now < time2))
                {
                    try
                    {
                        request.GetResponse();
                        flag = true;
                        continue;
                    }
                    catch (WebException)
                    {
                        continue;
                    }
                }

                this.StartSession(new InternetExplorerOptions().ToCapabilities());
            }

            private void Stop()
            {
                if ((this.driverServiceProcess != null) && !this.driverServiceProcess.HasExited)
                {
                    Uri requestUri = new Uri(this.ServiceUrl, "/shutdown");
                    DateTime time2 = DateTime.Now.Add(TimeSpan.FromSeconds(3.0));
                    HttpWebRequest request = WebRequest.Create(requestUri) as HttpWebRequest;
                    bool flag = false;
                    while (!flag && (DateTime.Now < time2))
                    {
                        try
                        {
                            request.GetResponse();
                            continue;
                        }
                        catch (WebException)
                        {
                            flag = true;
                            continue;
                        }
                    }
                    this.driverServiceProcess.WaitForExit();
                    this.driverServiceProcess.Dispose();
                    this.driverServiceProcess = null;
                }
            }

            protected virtual Response Execute(string driverCommandToExecute, Dictionary<string, object> parameters)
            {
                Command commandToExecute = new Command(this.sessionId, driverCommandToExecute, parameters);
                Response errorResponse = new Response();
                try
                {
                    errorResponse = InnerExecute(commandToExecute);
                }
                catch (WebException exception)
                {
                    errorResponse.Status = WebDriverResult.UnhandledError;
                    errorResponse.Value = exception;
                }

                return errorResponse;
            }

            public virtual Response InnerExecute(Command commandToExecute)
            {
                if (commandToExecute == null)
                {
                    throw new ArgumentNullException("commandToExecute", "commandToExecute cannot be null");
                }
                HttpWebRequest request = CommandInfoRepository.Instance.GetCommandInfo(commandToExecute.Name).CreateWebRequest(this.remoteServerUri, commandToExecute);
                request.Timeout = (int)this.serverResponseTimeout.TotalMilliseconds;
                request.Accept = "application/json, image/png";
                request.KeepAlive = this.enableKeepAlive;
                request.ServicePoint.ConnectionLimit = 0x7d0;

                if (request.Method == "POST")
                {
                    string parametersAsJsonString = commandToExecute.ParametersAsJsonString;
                    byte[] bytes = Encoding.UTF8.GetBytes(parametersAsJsonString);
                    request.ContentType = "application/json;charset=utf-8";
                    Stream requestStream = request.GetRequestStream();
                    requestStream.Write(bytes, 0, bytes.Length);
                    requestStream.Close();
                }

                return CreateResponse(request);
            }

            protected void StartSession(ICapabilities desiredCapabilities)
            {
                Dictionary<string, object> parameters = new Dictionary<string, object>();
                parameters.Add("desiredCapabilities", desiredCapabilities);
                Response response = this.Execute(DriverCommand.NewSession, parameters);
                Dictionary<string, object> rawMap = (Dictionary<string, object>)response.Value;
                DesiredCapabilities capabilities = new DesiredCapabilities(rawMap);
                this.capabilities = capabilities;
                this.sessionId = new OpenQA.Selenium.Remote.SessionId(response.SessionId);
            }

            private static Uri GetDriverServiceUrl(DriverService driverService)
            {
                Uri serviceUrl = null;
                if (driverService != null)
                {
                    serviceUrl = driverService.ServiceUrl;
                }
                return serviceUrl;
            }

            private static Response CreateResponse(WebRequest request)
            {
                Response response = new Response();
                HttpWebResponse webResponse = null;
                try
                {
                    webResponse = (HttpWebResponse)request.GetResponse();
                }
                catch (WebException exception)
                {
                    webResponse = (HttpWebResponse)exception.Response;
                }
                if (webResponse == null)
                {
                    throw new WebDriverException("No response from server for url " + request.RequestUri.AbsoluteUri);
                }
                string textOfWebResponse = GetTextOfWebResponse(webResponse);
                if ((webResponse.ContentType != null) && webResponse.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
                {
                    response = Response.FromJson(textOfWebResponse);
                }
                else
                {
                    response.Value = textOfWebResponse;
                }
                if ((webResponse.StatusCode < HttpStatusCode.OK) || (webResponse.StatusCode >= HttpStatusCode.BadRequest))
                {
                    if ((webResponse.StatusCode >= HttpStatusCode.BadRequest) && (webResponse.StatusCode < HttpStatusCode.InternalServerError))
                    {
                        response.Status = WebDriverResult.UnhandledError;
                    }
                    else if (webResponse.StatusCode >= HttpStatusCode.InternalServerError)
                    {
                        if (webResponse.StatusCode == HttpStatusCode.NotImplemented)
                        {
                            response.Status = WebDriverResult.UnknownCommand;
                        }
                        else if (response.Status == WebDriverResult.Success)
                        {
                            response.Status = WebDriverResult.UnhandledError;
                        }
                    }
                    else
                    {
                        response.Status = WebDriverResult.UnhandledError;
                    }
                }
                if (response.Value is string)
                {
                    response.Value = ((string)response.Value).Replace("\r\n", "\n").Replace("\n", Environment.NewLine);
                }
                return response;
            }

            private static string GetTextOfWebResponse(HttpWebResponse webResponse)
            {
                StreamReader reader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8);
                string str = reader.ReadToEnd();
                reader.Close();
                if (str.IndexOf('\0') >= 0)
                {
                    str = str.Substring(0, str.IndexOf('\0'));
                }
                return str;
            }

            public static int FindFreePort()
            {
                int port = 0;
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                try
                {
                    IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 0);
                    socket.Bind(localEP);
                    localEP = (IPEndPoint)socket.LocalEndPoint;
                    port = localEP.Port;
                }
                finally
                {
                    socket.Close();
                }
                
                return port;
            }
        }
    }
}
